import { Layers, Node, warn, Widget } from "cc";
import { UIContainer } from "./container/UIContainer";
import { UICallbacks, UIConfig, UILayerType } from "./Defines";
import { UIPopUp } from "./container/UIPopUp";
import { UIDialog } from "./container/UIDialog";
import { UINotify } from "./container/UINotify";
import { UIDelegateComponent } from "./UIDelegateComponent";
import { UIMap } from "./UIMap";


export class UIManager  {
    
    /** 界面根节点 */
    root: Node = null;
    /** 游戏界面特效层 */
    game: Node;
    /** 新手引导层 */
    guide: Node;
    /** 界面地图 */
    uiMap!: UIMap;

    /** 界面层 */
    private ui!: UIContainer;
    // /** 弹窗层 */
    private popup!: UIPopUp;
    /** 只能弹出一个的弹窗 */
    private dialog!: UIDialog;
    /** 游戏系统提示弹窗  */
    private system!: UIDialog;
    /** 消息提示控制器，请使用show方法来显示 */
    private notify!: UINotify;
   
    /** UI配置 */
    private configs: { [key: number]: UIConfig } = {};


    init(root: Node, configs: { [key: number]: UIConfig }) {
        this.configs = configs;

        this.root = root;
        this.game = new UIContainer("Game");
        this.ui = new UIContainer("UI");
        this.popup = new UIPopUp("PopUp");
        this.dialog = new UIDialog("Dialog");
        this.system = new UIDialog("System");
        this.notify = new UINotify("Notify");

        this.guide = this._createNode("Guide");

        this.root.addChild(this.game);
        this.root.addChild(this.ui);
        this.root.addChild(this.popup);
        this.root.addChild(this.dialog);
        this.root.addChild(this.system);
        this.root.addChild(this.notify);
        this.root.addChild(this.guide);

    }

    /**
     * 设置界面配置
     * @param uiId   要设置的界面id
     * @param config 要设置的配置
     */
    setConfig(uiId: number, config: UIConfig): void {
        this.configs[uiId] = config;
    }

    /**
     * 渐隐飘过提示
     * @param content 文本表示
     * @param useI18n 是否使用多语言
     */
    toast(content: string, useI18n: boolean = false) {
        // this.notify.show(content, useI18n)
    }

    /**
     * 设置界面地图配置
     * @param data 界面地图数据
     */
    setUIMap(data: any) {
        if (this.uiMap == null) {
            this.uiMap = new UIMap();
        }
        this.uiMap.init(this, data);
    }

    open(uiId: number, uiArgs?: any, callbacks?: UICallbacks) {
        const config = this.configs[uiId];
      
        if (config == null) {
            console.warn(`打开编号为【${uiId}】的界面失败，配置信息不存在`);
            console.warn(`配置信息为`, this.configs);
            return;
        }

          switch (config.layer) {
            case UILayerType.UI:
                this.ui.add(uiId, config, uiArgs, callbacks);
                break;
            case UILayerType.PopUp:
                this.popup.add(uiId, config, uiArgs, callbacks);
                break;
            case UILayerType.Dialog:
                this.dialog.add(uiId, config, uiArgs, callbacks);
                break;
            case UILayerType.System:
                this.system.add(uiId, config, uiArgs, callbacks);
                break;
        }
    }

    /**
     * 异步打开一个窗口
     * @param uiId          窗口唯一编号
     * @param uiArgs        窗口参数
     * @example 
     * let node = await uiManager.openAsync(UIID.Loading);
     */
    async openAsync(uiId: number, uiArgs: any = null): Promise<Node | null> {
        return new Promise<Node | null>((resolve, reject) => {
            const callbacks: UICallbacks = {
                onAdded: (node: Node, params: any) => {
                    resolve(node)
                }
            };
            this.open(uiId, uiArgs, callbacks);
        });
    }

    /**
     * 缓存中是否存在指定标识的窗口
     * @param uiId 窗口唯一标识
     * @example
     * uiManager.has(UIID.Loading);
     */
    has(uiId: number): boolean {
        let config = this.configs[uiId];
        if (config == null) {
            warn(`编号为【${uiId}】的界面失败，配置信息不存在`);
            return false;
        }

        let result = false;
        switch (config.layer) {
            case UILayerType.UI:
                result = this.ui.has(config.path);
                break;
            case UILayerType.PopUp:
                result = this.popup.has(config.path);
                break;
            case UILayerType.Dialog:
                result = this.dialog.has(config.path);
                break;
            case UILayerType.System:
                result = this.system.has(config.path);
                break;
        }
        return result;
    }


    /**
     * 移除指定标识的窗口
     * @param uiId         窗口唯一标识
     * @example
     * uiManager.close(UIID.Loading);
     */
    close(uiId: number) {
        const config = this.configs[uiId];
        if (config == null) {
            warn(`删除编号为【${uiId}】的界面失败，配置信息不存在`);
            return;
        }

        switch (config.layer) {
            case UILayerType.UI:
                this.ui.remove(config.path, config.isDestroy);
                break;
            case UILayerType.PopUp:
                this.popup.remove(config.path, config.isDestroy);
                break;
            case UILayerType.Dialog:
                this.dialog.remove(config.path, config.isDestroy);
                break;
            case UILayerType.System:
                this.system.remove(config.path, config.isDestroy);
                break;
        }
    }

     /**
     * 删除一个通过this框架添加进来的节点
     * @param node          窗口节点
     * @param isDestroy     移除后是否释放
     * @example
     * removeByNode(cc.Node);
     */
    removeByNode(node: Node, isDestroy: boolean = false) {
        if (node instanceof Node) {
            let comp = node.getComponent(UIDelegateComponent);
            if (comp && comp.viewParams) {
                // @ts-ignore 注：不对外使用
                (node.parent as UIContainer).removeByUuid(comp.viewParams.uuid, isDestroy);
            }
            else {
                warn(`当前删除的node不是通过界面管理器添加到舞台上`);
                node.destroy();
            }
        }
    }

    /**
     * 清除所有窗口
     * @param isDestroy 移除后是否释放
     * @example
     * uiManager.clear();
     */
    clear(isDestroy: boolean = false) {
        this.ui.clear(isDestroy);
        this.popup.clear(isDestroy);
        this.dialog.clear(isDestroy);
        this.system.clear(isDestroy);
    }

    /**
     * 创建2D节点
     * @param name 
     * @returns 
     */
    private _createNode(name: string) {
        const node = new Node(name);
        node.layer = Layers.Enum.UI_2D;
        const w: Widget = node.addComponent(Widget);
        w.isAlignLeft = w.isAlignRight = w.isAlignTop = w.isAlignBottom = true;
        w.left = w.right = w.top = w.bottom = 0;
        w.alignMode = Widget.AlignMode.ON_WINDOW_RESIZE;
        w.enabled = true;
        return node;
    }
}

export const uiManager = new UIManager();